type Handler = (e: MouseEvent) => void;
type Events = "click";

class DocumentEvents {
  private events: { [P in Events]?: Handler[] } = {};
  private nativeEvents: { [P in Events]?: Handler } = {};
  private initializedEvents = new Set<Events>();
  private init(type: Events) {
    if (this.initializedEvents.has(type)) {
      return;
    }
    this.initializedEvents.add(type);
    this.events[type] = [];
    this.nativeEvents[type] = (e: MouseEvent) => {
      this.events[type]!.forEach((handler) => handler(e));
    };
    document.addEventListener(type, this.nativeEvents[type]);
  }

  bind(type: Events, handler: Handler) {
    this.init(type);
    this.events[type]!.push(handler);
  }

  off(type: Events, handler: Handler) {
    if (!this.initializedEvents.has(type)) {
      return;
    }
    this.events[type] = this.events[type]!.filter((h) => h !== handler);
    if (this.events[type].length === 0) {
      this.initializedEvents.delete(type);
      document.removeEventListener(type, this.nativeEvents[type]!);
      delete this.events[type];
      delete this.nativeEvents[type];
    }
  }
}

const documentEvents = new DocumentEvents();

export default documentEvents;
